use crate::audio_codes::{g711::G711A, AudioCodes, Codec};
use bytes::{Buf, Bytes, BytesMut};
use std::{
	io::{self, SeekFrom},
	path::Path,
};
use tokio::{
	fs::File,
	io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt},
};
use tools::{error::Error, ResultEx};
///针对Wav文件的编解码器.
/// 写入文件的处理
/// 读文件的处理..
/// 此对象在用来向远端发送过程中,data内数据会被消耗掉,因此如果需要保存,使用时需要克隆一份.
/// 目前的类里面只保存g711a的编码格式数据.
/// 暂时只支持单声道的8000采样率.
#[derive(Debug, Clone)]
pub(crate) struct WavBuf {
	///这个不是完整文件的数据内容,而是对应当前音频格式,可以直接发送的内容
	pub(crate) data: Bytes,
	pub(crate) sample_rate: u32,
	//通道的数量 1:单声道.2:双声道
	// pub(crate) channel_num: u8,
	pub(crate) data_codes: AudioCodes,
}

impl WavBuf {
	///从文件系统获取一个wav文件对象.
	pub(crate) async fn from_file(path: impl AsRef<Path>) -> ResultEx<Self> {
		let mut file = File::open(path).await?;
		let mut temp = BytesMut::with_capacity(4);
		let _ = file.read_buf(&mut temp).await?;
		if *temp != *b"RIFF" {
			return Err(Error::IOError("wav文件格式不正确.需要 RIFF 节".to_owned()));
		}
		temp.clear();
		let _ = file.read_buf(&mut temp).await?;

		let file_len = temp.get_u32_le();
		let mut buf = BytesMut::with_capacity(file_len as usize);
		let _ = file.read_buf(&mut buf).await?;
		let mut buf = buf.freeze();

		if *buf.split_to(4) != *b"WAVE" {
			return Err(Error::IOError(
				"wav文件格式不正确.需要 WAVE 类型".to_owned(),
			));
		}
		if *buf.split_to(4) != *b"fmt " {
			return Err(Error::IOError("wav文件格式不正确.需要 fmt 节..".to_owned()));
		}
		let mut chunk_len = buf.get_u32_le();
		let codes = AudioCodes::from_wav_code_type(buf.get_u16_le())?;
		//目前还不支持双声道
		if buf.get_u16_le() > 1 {
			return Err(Error::IOError("wav文件格式不正确.需要单声道".to_owned()));
		}
		if buf.get_u32_le() != 8000 {
			return Err(Error::IOError(
				"wav文件格式不正确.需要 8000 采样率".to_owned(),
			));
		}
		//跳过不需要处理的字节数
		buf.advance((chunk_len - 8) as usize);

		let mut chunk_name = buf.split_to(4);

		//可能存在 多个 fact 节或者LIST..跳过就是
		while *chunk_name == *b"fact" || *chunk_name == *b"LIST" {
			chunk_len = buf.get_u32_le();
			buf.advance(chunk_len as usize);
			chunk_name = buf.split_to(4);
		}

		//data节就是要的数据..目前代码当中保存pcma的数据,以便于后续使用,不需要再转码.
		if *chunk_name != *b"data" {
			return Err(Error::IOError("wav文件格式不正确.需要 data 节".to_owned()));
		}
		chunk_len = buf.get_u32_le();
		//跳过可能存在的后面的部分
		let _ = buf.split_off(chunk_len as usize);

		let buf = match codes {
			AudioCodes::G711A => buf,
			AudioCodes::PCM => G711A::decode_from_pcm(buf),
			AudioCodes::Rfc2833 | AudioCodes::Unknow => {
				return Err(Error::IOError("无法解析的格式".to_owned()))
			}
		};

		Ok(Self {
			data: buf,
			sample_rate: 8000,
			// channel_num: 1,
			data_codes: AudioCodes::G711A,
		})
	}
}

///写入wav文件对象.
/// 只所以要这个对象,是因为Flie对象是不能进行clone的.所以只能单独出来一个对象进行写入的控制
#[derive(Debug)]
pub(crate) struct WriteWavFile {
	//这个用Option的原因是调用new的时候没有进入异步操作
	file: File,
	#[allow(unused)]
	codes: AudioCodes,
	channel_num: u8,
	left_seek: u64,
	right_seek: u64,
}

///对应PAMA格式的wav文件头写入的数据
const PCMA_DUAL_TRACK_HEAD:&[u8] = b"RIFF\x00\x00\x00\x00WAVEfmt\x20\x12\x00\x00\x00\x06\x00\x02\x00\x40\x1f\x00\x00\x80\x3e\x00\x00\x02\x00\x08\x00\x00\x00fact\x04\x00\x00\x00\x00\x00\x00\x00data\x00\x00\x00\x00";
impl WriteWavFile {
	pub(crate) async fn new(file_path: String, codes: AudioCodes, channel_num: u8) -> ResultEx<Self> {
		let mut file = File::create(file_path).await?;

		file.write_all(PCMA_DUAL_TRACK_HEAD).await?;
		//修改文件的编码格式..当前已经写入的是针对PCMA的格式,双声道.其他格式需要修改
		if AudioCodes::G711A != codes || channel_num != 2 {
			file.seek(SeekFrom::Start(0x14)).await?;
			file.write_u16_le(codes.to_wav_code_type() as u16).await?;
			file.write_u16_le(channel_num as u16).await?;
			file.write_u32_le(codes.sample_rate()).await?;
			file
				.write_u32_le((codes.sample_rate() * channel_num as u32 * codes.wav_bits() as u32) / 8)
				.await?;
			file
				.write_u16_le((channel_num as u16 * codes.wav_bits()) / 8)
				.await?;
			//定长度是12,这里写入u16,是因为后面直接跳出...不再写的原因
			file.write_u16_le(codes.wav_bits()).await?;

			file
				.seek(SeekFrom::Start(PCMA_DUAL_TRACK_HEAD.len() as u64))
				.await?;
		}

		Ok(Self {
			file,
			left_seek: PCMA_DUAL_TRACK_HEAD.len() as u64,
			right_seek: PCMA_DUAL_TRACK_HEAD.len() as u64 + 1,
			codes,
			channel_num,
		})
	}

	pub(crate) async fn write_wav_file_buf(&mut self, buf: &[u8], is_left: bool) -> ResultEx<()> {
		match self.channel_num {
			//目前这里就是根据每次一个字节写入,如果是多字节,这里还要特殊处理一下
			2 => {
				//开始定位
				if is_left {
					self.file.seek(SeekFrom::Start(self.left_seek)).await?;
				} else {
					self.file.seek(SeekFrom::Start(self.right_seek)).await?;
				};

				for i in 0..buf.len() {
					self.file.write_u8(buf[i]).await?;
					self.file.seek(SeekFrom::Current(1)).await?;

					if is_left {
						self.left_seek += 2;
					} else {
						self.right_seek += 2;
					};
				}

				Ok(())
			}
			1 => {
				self.file.write_all(buf).await?;
				self.left_seek += buf.len() as u64;

				Ok(())
			}
			_ => Err(Error::LogicalError("声道数不正确")),
		}
	}

	///结束一个文件的写入,这里要修改对应的长度
	pub(crate) async fn write_wav_file_end(&mut self) -> io::Result<()> {
		let max_len = self.left_seek.max(self.right_seek);

		//写入RIF的长度
		self.file.seek(SeekFrom::Start(4)).await?;
		self.file.write_u32_le((max_len - 8).try_into().unwrap_or(0)).await?;

		let head_len = PCMA_DUAL_TRACK_HEAD.len() as u64;
		let data_len = max_len - head_len;
		//写data的长度
		self.file.seek(SeekFrom::Start(head_len - 4)).await?;
		self.file.write_u32_le(data_len.try_into().unwrap_or(0)).await?;
		//写fact的内容..也是data的长度
		self.file.seek(SeekFrom::Start(head_len - 12)).await?;
		self.file.write_u32_le(data_len.try_into().unwrap_or(0)).await?;

		self.file.flush().await?;

		Ok(())
	}
}
